package com.eerl.pdev.ori.erl;

import com.eerl.pdev.ProjectContainer;
import com.eerl.pdev.util.EToolPluginConsoleToolWindowFactory;
import com.eerl.pdev.werl.ERpcReturn;
import com.ericsson.otp.erlang.OtpErlangList;
import com.ericsson.otp.erlang.OtpErlangObject;
import com.ericsson.otp.erlang.OtpErlangString;
import com.ericsson.otp.erlang.OtpErlangTuple;
import com.intellij.openapi.project.Project;

import java.util.regex.Pattern;

// 起个名字真难
public class ErlCommon {
    // 生成的初始化int解析模块名称
    public static final String INT_BREAK_INIT_MOD = "idea_gen_int_break_init_mod___";
    // 生成的int模块初始化执行函数名称 -- 通过该模块的初始化函数将断点模块进行解析、断点、变量提取
    public static final String INT_BREAK_INIT_FUN = "idea_gen_int_break_init_fun___";
    public static final String INT_BREAK_CLOSE_FUN = "idea_gen_int_break_close_fun___";
    public static final String INT_BREAK_CLOSE_MOD = "idea_gen_int_break_close_mod___";

    // 生成的自动将string转为ast并编译加载的beam
    public static final String ERL_AUTO_GEN_LOAD_BEAM_MOD = "idea_gen_auto_gen_load_beam_mod___";
    public static final String ERL_AUTO_GEN_LOAD_BEAM_FUN = "idea_gen_auto_gen_load_beam_fun__";

    // erlang var 提取正则
    // public static final Pattern EVAR_PATTERN = Pattern.compile("(?<![?#:a-zA-Z0-9_])[A-Z_][A-Za-z0-9_]*(?![(:])|\\[([A-Z_][A-Za-z0-9_]*(?:,[A-Z_][A-Za-z0-9_]*)*)]");
    // 遇到换行停止
    public static final Pattern EVAR_PATTERN = Pattern.compile("(?<![?#:a-zA-Z0-9_])[A-Z_][A-Za-z0-9_]*(?![(:])|\\[([A-Z_][A-Za-z0-9_]*(?:,[A-Z_][A-Za-z0-9_]*)*)](?=[\\s\\S]*?(?:\\n|$))");

    public static void autoCodeStrCompileAndLoad(Project project, OriErlangNode eRpc) {
        // 暂时借用下
        String autoLoadCodeSuccessRet = ERpcReturn.eRpcCallReturnTemplate(true, "\"\"", "\"\"");
        String autoLoadCodeFailRet = ERpcReturn.eRpcCallReturnTemplate(false, "lists:flatten(io_lib:format(\"~w, ~w\", [_T, _R]))", "\"\"");
        String autoLoadCodeStr = """
                -module(%s).
                -export([%s/1]).
                %s(NeedLoadCodeStr) ->
                    try
                        AST = merl:quote(NeedLoadCodeStr),
                        merl:compile_and_load(AST),
                        %s
                    catch
                        _T:_R -> %s
                    end.
                """.formatted(ERL_AUTO_GEN_LOAD_BEAM_MOD, ERL_AUTO_GEN_LOAD_BEAM_FUN, ERL_AUTO_GEN_LOAD_BEAM_FUN, autoLoadCodeSuccessRet, autoLoadCodeFailRet);
        OtpErlangList args = new OtpErlangList(new OtpErlangObject[]{new OtpErlangString(autoLoadCodeStr)});
        OtpErlangTuple autoLoadCallRet = eRpc.call("merl", "quote", args);
        EToolPluginConsoleToolWindowFactory.printSimpleToConsole(project, "merl quote beam load mod success...");
        OtpErlangList args2 = new OtpErlangList(autoLoadCallRet.elementAt(ERpcReturn.DATA_POS));
        EToolPluginConsoleToolWindowFactory.debugPrint(project, "自编译模块: " + autoLoadCallRet);
        OtpErlangTuple _loadRet = eRpc.call("merl", "compile_and_load", args2);
        EToolPluginConsoleToolWindowFactory.printSimpleToConsole(project, "beam ast translate and compile load mod success...");
        EToolPluginConsoleToolWindowFactory.debugPrint(project, "加载自编译模块" + _loadRet.toString());
    }

    public static void compileAndLoad(Project project, String breakCodeStr, OriErlangNode eRpc) {
        OtpErlangList args = new OtpErlangList(new OtpErlangObject[]{new OtpErlangString(breakCodeStr)});
        OtpErlangTuple breakRet = eRpc.call(ERL_AUTO_GEN_LOAD_BEAM_MOD, ERL_AUTO_GEN_LOAD_BEAM_FUN, args);
        if (ERpcReturn.isSuccess(breakRet)) {
            EToolPluginConsoleToolWindowFactory.debugPrint(project, "compile and load success, ret: " + breakRet);
        } else {
            EToolPluginConsoleToolWindowFactory.errSimpleToConsole(project, "compile and load success fail: " + breakRet);
        }
        EToolPluginConsoleToolWindowFactory.debugPrint(project, "compile and load code str: \n" + breakCodeStr);
    }

    public static void loadBeamAndExec(Project project, String codeStr, String codeExecModName, String codeExecFunName) {
        EToolPluginConsoleToolWindowFactory.debugPrint(project, "load Code => " + codeStr);
        OriErlangNode oriErlangNode = ProjectContainer.getInstance(project).get(OriErlangNode.class);
        compileAndLoad(project, codeStr, oriErlangNode);
        EToolPluginConsoleToolWindowFactory.debugPrint(project, "exec load mod fun [" + codeExecModName + ":" + codeExecFunName + "]");
        OtpErlangTuple call = oriErlangNode.call(codeExecModName, codeExecFunName, new OtpErlangList());
        if (ERpcReturn.isSuccess(call)) {
            EToolPluginConsoleToolWindowFactory.debugPrint(project, "start beam mod success, ret: " + call);
        } else {
            EToolPluginConsoleToolWindowFactory.errSimpleToConsole(project, "start beam mod fail: " + call);
        }
    }

}
